package utils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import objects.BoardData;
import objects.Card;
import objects.CardType;
import objects.Character;
import objects.Envelope;
import objects.Player;
import objects.Room;
import objects.Weapon;
public class ValidityManager 
{
	public static String IsValidBoardData(BoardData bdToCheck)
	{
		if (bdToCheck == null)
		{
			return "Board Data is empty!!";
		}
		int[] arrWeaponIDs = new int[Weapon.values().length];
		int[] arrRoomIDs = new int[Room.values().length];
		int[] arrCharIDs = new int[Character.values().length];
		Map<String, Integer> mpNames = new HashMap<String,Integer>();
		Map<String, Integer> mpCharNames = new HashMap<String,Integer>();
		Map<Integer, Integer> mpCharOrders = new HashMap<Integer,Integer>();
		List<Player> lstPlayers = bdToCheck.getPlayers();
		
		if (!(lstPlayers.size() <= 6 && lstPlayers.size() >= 3))
		{
			return "Wrong amount of players. Game cannot start with " + 
					lstPlayers.size() + " Players";
		}
		
		for (Player plCurr : lstPlayers)
		{
			if (plCurr.getName().replaceAll("\\s","").toLowerCase().isEmpty())
			{
				return "Player name cannot be empty or to contain only spaces.";
			}
			else
			{
				mpNames.put(plCurr.getName(), 0);
			}
			
			if (plCurr.getCharacter() == null)
			{
				return "Player must have a character.";
			}
			else
			{
				mpCharNames.put(plCurr.getCharacter().name(), 0);
			}
			
			if (plCurr.getType() == null)
			{
				return "Player " + plCurr.getName() + " must have a valid type. (HUMAN/COMPUTER)";
			}
			
			if (!(plCurr.getType().equals("HUMAN") || plCurr.getType().equals("COMPUTER")))
			{
				return "Player " + plCurr.getName() + " must have a valid type. (HUMAN/COMPUTER)";
			}
			
			if (plCurr.getOrder() > lstPlayers.size() || plCurr.getOrder() <= 0 )
			{
				return "Error! Player order is not between 1 and " + lstPlayers.size();
			}
			else
			{
				mpCharOrders.put(plCurr.getOrder(), 0);
			}

		}
		
		for (Player plCurr : lstPlayers)
		{	
			if (mpNames.get(plCurr.getName()) != 0 )
			{
				return "Duplicate player name found.";
			}
			else
			{
				mpNames.put(plCurr.getName(), mpNames.get(plCurr.getName()) + 1);
			}
			
			if (mpCharNames.get(plCurr.getCharacter().name()) != 0)
			{
				return "Duplicate character for player found.";
			}
			else
			{
				mpCharNames.put(plCurr.getCharacter().name(), 1);
			}
						
			if (mpCharOrders.get(plCurr.getOrder()) != 0)
			{
				return "Duplicate order found.";
			}
			else
			{
				mpCharOrders.put(plCurr.getOrder(), 1);
			}
			
			List<Card> arrCards = plCurr.getCards();
			for (Card crdCurr : arrCards)
			{
				CardType cardType = crdCurr.getType();
				switch (cardType) 
		        {
		            case CHARACTER:
		            	{
		            		int nValue = arrCharIDs[Character.valueOf(crdCurr.getName()).ordinal()];
		            		if (nValue == 0)
		            		{
		            			arrCharIDs[Character.valueOf(crdCurr.getName()).ordinal()]++;
		            		}
		            		else
		            		{
		            			return "Duplicate card found. Player: " + plCurr.getName() + 
		            					" Card: " + crdCurr.getName();
		            		}
		            		break;
		            	}
		            case ROOM:
		            	{
		            		int nValue = arrRoomIDs[Room.valueOf(crdCurr.getName()).ordinal()];
		            		if (nValue == 0)
		            		{
		            			arrRoomIDs[Room.valueOf(crdCurr.getName()).ordinal()]++;
		            		}
		            		else
		            		{
		            			return "Duplicate card found. Player: " + plCurr.getName() + 
		            					" Card: " + crdCurr.getName();
		            		}
		            		break;
		            	}
		            case WEAPON:
		            	{
		            		int nValue = arrWeaponIDs[Weapon.valueOf(crdCurr.getName()).ordinal()];
		            		if (nValue == 0)
		            		{
		            			arrWeaponIDs[Weapon.valueOf(crdCurr.getName()).ordinal()]++;
		            		}
		            		else
		            		{
		            			return "Duplicate card found. Player: " + plCurr.getName() + 
		            					" Card: " + crdCurr.getName();
		            		}
		            		break;
		            	}
		        }
			}
		}
		
		Envelope envToCheck = bdToCheck.getEnvelope();
		Card crdCharCheck = envToCheck.getCharacterCard();
		int nValue;
		nValue = arrCharIDs[Character.valueOf(crdCharCheck.getName()).ordinal()];
		if (nValue == 0)
		{
			arrCharIDs[Character.valueOf(crdCharCheck.getName()).ordinal()]++;
		}
		else
		{
			return "Duplicate card found for envelope. Card: " + crdCharCheck.getName();
		}
		
		Card crdRoomToCheck = envToCheck.getRoomCard();
		nValue = arrRoomIDs[Room.valueOf(crdRoomToCheck.getName()).ordinal()];
		if (nValue == 0)
		{
			arrRoomIDs[Room.valueOf(crdRoomToCheck.getName()).ordinal()]++;
		}
		else
		{
			return "Duplicate card found for envelope. Card: " + crdRoomToCheck.getName();
		}
		
		Card crdWeaponToCheck = envToCheck.getWeaponCard();
		nValue = arrWeaponIDs[Weapon.valueOf(crdWeaponToCheck.getName()).ordinal()];
		if (nValue == 0)
		{
			arrWeaponIDs[Weapon.valueOf(crdWeaponToCheck.getName()).ordinal()]++;
		}
		else
		{
			return "Duplicate card found for envelope. Card: " + crdWeaponToCheck.getName();
		}
		
		for (int i=0; i<arrCharIDs.length; i++)
		{
			if (arrCharIDs[i] != 1)
				return "Error! Missing card! " + Character.values()[i].name();
		}
		
		for (int i=0; i<arrRoomIDs.length; i++)
		{
			if (arrRoomIDs[i] != 1)
				return "Error! Missing card! " + Room.values()[i].name();
		}
		
		for (int i=0; i<arrWeaponIDs.length; i++)
		{
			if (arrWeaponIDs[i] != 1)
				return "Error! Missing card! " + Weapon.values()[i].name();
		}
		
		return "";
	}
}
